package com.fly.hello.web;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.http.MediaType;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * RestPicController
 * 
 * @author 00fly
 * @version [版本号, 2021年9月28日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Slf4j
@Api(tags = "图片接口-api")
@RestController
@RequestMapping("/show")
@ConditionalOnWebApplication
public class RestPicController
{
    byte[] lock = new byte[0];
    
    Resource[] resources = {};
    
    Queue<Integer> quque = new ConcurrentLinkedQueue<>();
    
    @PostConstruct
    private void init()
    {
        try
        {
            resources = new PathMatchingResourcePatternResolver().getResources(ResourceUtils.CLASSPATH_URL_PREFIX + "data/pic/**/*.jpg");
            if (resources.length < 4)
            {
                log.error("############### 请在[resources/data/pic/]目录放入不少于4张jpg图片 ###############");
            }
        }
        catch (IOException e)
        {
            log.error(e.getMessage(), e);
        }
    }
    
    @ApiOperation("图片")
    @GetMapping(value = {"/girl", "/pic"}, produces = MediaType.IMAGE_JPEG_VALUE)
    public byte[] showPic()
        throws IOException
    {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(createImage(), "jpg", os);
        return os.toByteArray();
    }
    
    @ApiOperation("pic1")
    @GetMapping(value = "/pic1", produces = MediaType.IMAGE_JPEG_VALUE)
    public byte[] showPic1()
        throws IOException
    {
        return IOUtils.toByteArray(resources[getIndex()].getInputStream());
    }
    
    @ApiOperation("pic2")
    @GetMapping(value = "/pic2", produces = MediaType.IMAGE_JPEG_VALUE)
    public byte[] showPic2()
        throws IOException
    {
        BufferedImage image = ImageIO.read(resources[getIndex()].getInputStream());
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "jpg", os);
        return os.toByteArray();
    }
    
    @ApiOperation("pic3")
    @GetMapping(value = "/pic3", produces = MediaType.IMAGE_JPEG_VALUE)
    public void showPic3(HttpServletResponse response)
        throws IOException
    {
        // setHeader注解写法?
        response.setHeader("Cache-Control", "no-store, no-cache");
        BufferedImage image = ImageIO.read(resources[getIndex()].getInputStream());
        ImageIO.write(image, "jpg", response.getOutputStream());
    }
    
    @ApiOperation("pic4")
    @GetMapping(value = "/pic4", produces = MediaType.IMAGE_JPEG_VALUE)
    public void showPic4(HttpServletResponse response)
        throws IOException
    {
        response.setHeader("Cache-Control", "no-store, no-cache");
        IOUtils.copy(resources[getIndex()].getInputStream(), response.getOutputStream());
    }
    
    @ApiOperation("文件下载-支持file")
    @GetMapping(value = "/down", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void down(HttpServletResponse response)
        throws IOException
    {
        if (ResourceUtils.isFileURL(ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX)))
        {
            List<Path> filePaths = new ArrayList<>();
            Stream.of(new ClassPathResource("data/pic").getFile().listFiles()).forEach(lib -> filePaths.add(lib.toPath()));
            
            // 压缩多个文件到zip文件中
            String filename = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmss");
            response.setHeader("Content-Disposition", "attachment;filename=imgs_" + filename + ".zip");
            try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream()))
            {
                for (Path path : filePaths)
                {
                    try (InputStream inputStream = Files.newInputStream(path))
                    {
                        zipOutputStream.putNextEntry(new ZipEntry(path.getFileName().toString()));
                        StreamUtils.copy(inputStream, zipOutputStream);
                        zipOutputStream.flush();
                    }
                }
            }
        }
    }
    
    @ApiOperation("文件下载2-支持file、jar")
    @GetMapping(value = "/down2", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void down2(HttpServletResponse response)
        throws IOException
    {
        String filename = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmss");
        response.setHeader("Content-Disposition", "attachment;filename=imgs_" + filename + ".zip");
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream()))
        {
            Stream.of(resources).forEach(r -> {
                try
                {
                    InputStream inputStream = r.getInputStream();
                    zipOutputStream.putNextEntry(new ZipEntry(r.getFilename()));
                    StreamUtils.copy(inputStream, zipOutputStream);
                    zipOutputStream.flush();
                }
                catch (IOException e)
                {
                    log.error(e.getMessage(), e);
                }
            });
        }
    }
    
    /**
     * createImage 生成图片
     * 
     * @return
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    private BufferedImage createImage()
        throws IOException
    {
        if (resources.length < 4)
        {
            log.info("############### 请在[resources/data/pic/]目录放入不少于4张jpg图片 ###############");
            return new BufferedImage(400, 400, BufferedImage.TYPE_BYTE_GRAY);
        }
        // 取图片
        int index = getIndex();
        return ImageIO.read(resources[index].getInputStream());
    }
    
    private int getIndex()
    {
        int index;
        if (quque.size() < 3)
        {
            synchronized (lock)
            {
                // 集中1次生成，多次使用
                int max = resources.length;
                while (quque.size() < max)
                {
                    index = RandomUtils.nextInt(0, max);
                    if (!quque.contains(index))
                    {
                        quque.add(index);
                    }
                }
            }
            log.info("{}", quque);
        }
        index = quque.poll();
        log.info("{} <= {} , ", index, quque);
        return index;
    }
}
